
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ManagedAPI;

namespace UnitTest.Derived
{
	/// <summary>
	/// Summary description for MethodTypeTest
	/// </summary>
	[TestClass]
	public class MethodTypeTest
	{
		public MethodTypeTest()
		{

		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		private static bool mOpenResult;
		[TestInitialize()]
		public void MyTestInitialize()
		{
			mOpenResult = Database.Open(UnderstandGlobalData.GetFileName());
			Assert.IsTrue(mOpenResult);
		}
		//
		// Use TestCleanup to run code after each test has run
		[TestCleanup()]
		public void MyTestCleanup()
		{
			Database.Close();
			mOpenResult = false;
		}
		//
		#endregion

		[TestMethod]
		public void MethodTest_Constructor()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				Assert.AreEqual("classes.h", fileEnt.NameShort);
				Assert.IsTrue(fileEnt != null);

				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				Assert.AreEqual(5, classtypes.Length);
				Assert.IsTrue(classtypes != null);

				ClassType mommy = classtypes[3];
				Assert.AreEqual("Mommy", mommy.NameLong);
				MethodType[] methods = mommy.GetMethods();
				Assert.AreEqual(8, methods.Length);
				MethodType ctor = methods[0];

				Assert.AreEqual("Mommy::Mommy", ctor.NameLong);
				Assert.AreEqual("C Public Member Function", ctor.KindName);
				Assert.IsTrue(ctor.IsPublic);
				Assert.AreEqual(null, ctor.TypeText); // This is the ctor, hence a special case
				Assert.AreEqual(null, ctor.Parameters);
				Assert.AreEqual("()", ctor.GetParameters(false));
				Assert.AreEqual("()", ctor.GetParameters(true));
				Assert.AreEqual("Mommy::Mommy()", ctor.ToString());
				Assert.AreEqual("", ctor.Attributes);
				Assert.IsTrue(ctor.IsConstructor);
				Assert.IsFalse(ctor.IsAbstract);
				Assert.IsFalse(ctor.IsPrivate);
				Assert.IsFalse(ctor.IsProtected);
				Assert.IsFalse(ctor.IsStatic);
				Assert.IsFalse(ctor.IsVirtual);

				MethodType foom = methods[3];
				Assert.IsFalse(foom.IsPublic);
			}
		}
		[TestMethod]
		public void MethodTest_Member_A()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType fn_one = methods[1];

				Assert.AreEqual("Mommy::fn_one", fn_one.NameLong);
				Assert.AreEqual("C Public Member Function", fn_one.KindName);
				Assert.AreEqual("char *", fn_one.TypeText); // The return type
				Assert.IsTrue(null != fn_one.Parameters);
				Assert.AreEqual("(char *)", fn_one.GetParameters(false));
				Assert.AreEqual("(char *buf)", fn_one.GetParameters(true));
				Assert.AreEqual(1, fn_one.Parameters.Length);
				Entity param = fn_one.Parameters[0];
				Assert.IsTrue(param != null);
				Assert.AreEqual("char *", param.TypeText);
				Assert.AreEqual("buf", param.NameShort);
				Assert.AreEqual("char * Mommy::fn_one(char *buf)", fn_one.ToString());
				Assert.AreEqual("", fn_one.Attributes);
				Assert.IsFalse(fn_one.IsConstructor);
				Assert.IsFalse(fn_one.IsAbstract);
				Assert.IsFalse(fn_one.IsPrivate);
				Assert.IsFalse(fn_one.IsProtected);
				Assert.IsFalse(fn_one.IsStatic);
				Assert.IsFalse(fn_one.IsVirtual);

			}
		}

		[TestMethod]
		public void MethodTest_Member_B()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType fn_two = methods[2];

				Assert.AreEqual("Mommy::fn_two", fn_two.NameLong);
				Assert.AreEqual("C Public Member Function Virtual", fn_two.KindName);
				Assert.AreEqual("char *", fn_two.TypeText); // The return type
				Assert.IsTrue(null != fn_two.Parameters);
				Assert.AreEqual("(const char *)", fn_two.GetParameters(false));
				Assert.AreEqual("(const char *buf)", fn_two.GetParameters(true));
				Assert.AreEqual(1, fn_two.Parameters.Length);
				Entity param = fn_two.Parameters[0];
				Assert.IsTrue(param != null);
				param = fn_two.Parameters[0];
				Assert.IsTrue(param != null);
				Assert.AreEqual("const char *", param.TypeText);
				Assert.AreEqual("buf", param.NameShort);
				Assert.AreEqual("virtual char * Mommy::fn_two(const char *buf)", fn_two.ToString());
				Assert.AreEqual("virtual char * Mommy::fn_two(const char *buf)", fn_two.ToString(true, true));
				Assert.AreEqual("virtual char * Mommy::fn_two(const char *)", fn_two.ToString(true, false));
				Assert.AreEqual("virtual char * fn_two(const char *buf)", fn_two.ToString(false, true));
				Assert.AreEqual("virtual char * fn_two(const char *)", fn_two.ToString(false, false));
				Assert.AreEqual("virtual", fn_two.Attributes);
				Assert.IsFalse(fn_two.IsConstructor);
				Assert.IsFalse(fn_two.IsAbstract);
				Assert.IsFalse(fn_two.IsPrivate);
				Assert.IsFalse(fn_two.IsProtected);
				Assert.IsFalse(fn_two.IsStatic);
				Assert.IsTrue(fn_two.IsVirtual);

			}
		}

		[TestMethod]
		public void MethodTest_Member_C()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType foom = methods[3];

				Assert.AreEqual("Mommy::foom", foom.NameLong);
				Assert.AreEqual("C Private Member Const Function", foom.KindName);
				Assert.AreEqual("void", foom.TypeText); // The return type
				Assert.IsTrue(null == foom.Parameters);
				Assert.AreEqual("()", foom.GetParameters(false));
				Assert.AreEqual("()", foom.GetParameters(true));
				Assert.AreEqual("const void Mommy::foom()", foom.ToString());
				Assert.AreEqual("const", foom.Attributes);
				Assert.IsFalse(foom.IsConstructor);
				Assert.IsFalse(foom.IsAbstract);
				Assert.IsTrue(foom.IsPrivate);
				Assert.IsFalse(foom.IsProtected);
				Assert.IsFalse(foom.IsStatic);
				Assert.IsFalse(foom.IsVirtual);
			}
		}

		[TestMethod]
		public void MethodTest_Member_D()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType foob = methods[4];

				Assert.AreEqual("Mommy::foob", foob.NameLong);
				Assert.AreEqual("C Private Member Function Static", foob.KindName);
				Assert.AreEqual("void", foob.TypeText); // The return type
				Assert.IsTrue(null != foob.Parameters);
				Assert.AreEqual("(int a,float b,const char *c,char *d,const Older *& e,int *f)", foob.GetParameters(true));
				Assert.AreEqual("(int,float,const char *,char *,const Older *&,int *)", foob.GetParameters(false));
				Assert.AreEqual("static void Mommy::foob(int a,float b,const char *c,char *d,const Older *& e,int *f)", foob.ToString());
				Assert.AreEqual("static", foob.Attributes);
				Assert.IsFalse(foob.IsConstructor);
				Assert.IsFalse(foob.IsAbstract);
				Assert.IsTrue(foob.IsPrivate);
				Assert.IsFalse(foob.IsProtected);
				Assert.IsTrue(foob.IsStatic);
				Assert.IsFalse(foob.IsVirtual);
			}
		}

		[TestMethod]
		public void MethodTest_Member_E()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType foop = methods[5];

				Assert.AreEqual("Mommy::foop", foop.NameLong);
				Assert.AreEqual("C Protected Member Function", foop.KindName);
				Assert.AreEqual("void", foop.TypeText); // The return type
				Assert.IsTrue(null == foop.Parameters);
				Assert.AreEqual("()", foop.GetParameters(false));
				Assert.AreEqual("()", foop.GetParameters(true));
				Assert.AreEqual("void Mommy::foop()", foop.ToString());
				Assert.AreEqual("", foop.Attributes);
				Assert.IsFalse(foop.IsConstructor);
				Assert.IsFalse(foop.IsAbstract);
				Assert.IsFalse(foop.IsPrivate);
				Assert.IsTrue(foop.IsProtected);
				Assert.IsFalse(foop.IsStatic);
				Assert.IsFalse(foop.IsVirtual);
			}
		}

		[TestMethod]
		public void MethodTest_Member_F()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType foopper = methods[6];

				Assert.AreEqual("Mommy::foopper", foopper.NameLong);
				Assert.AreEqual("C Protected Member Function Static", foopper.KindName);
				Assert.AreEqual("void", foopper.TypeText); // The return type
				Assert.IsTrue(null == foopper.Parameters);
				Assert.AreEqual("static void Mommy::foopper()", foopper.ToString());
				Assert.AreEqual("static", foopper.Attributes);
				Assert.IsFalse(foopper.IsConstructor);
				Assert.IsFalse(foopper.IsAbstract);
				Assert.IsFalse(foopper.IsPrivate);
				Assert.IsTrue(foopper.IsProtected);
				Assert.IsTrue(foopper.IsStatic);
				Assert.IsFalse(foopper.IsVirtual);
			}
		}

		[TestMethod]
		public void MethodTest_Pure()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType giff = classtypes[4];
				MethodType[] methods = giff.GetMethods();
				MethodType pureFunc = methods[0];
				Assert.AreEqual("myPureFunction", pureFunc.NameSimple);
				Entity[] paramList = pureFunc.Parameters;
				// Pure virtual functions do not have Parameter references...
				Assert.AreEqual(null, paramList);

				Assert.IsTrue(pureFunc.IsAbstract);
				Assert.IsTrue(pureFunc.IsVirtual);
				// But you can get a parameter string from a pure virtual function
				String temp = pureFunc.GetParameters(true);
				Char[] splitter = {',','(',')'};
				String[] splits = temp.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
				Assert.AreEqual(3, splits.Length);
				Assert.AreEqual("const char *A", splits[0]);
				Assert.AreEqual("const Older *B", splits[1]);
				Assert.AreEqual("Derived & C", splits[2]);

				temp = pureFunc.GetParameters(false);
				splits = temp.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
				Assert.AreEqual(3, splits.Length);
				Assert.AreEqual("const char *", splits[0]);
				Assert.AreEqual("const Older *", splits[1]);
				Assert.AreEqual("Derived &", splits[2]);
			}
		}

		[TestMethod]
		public void MethodTest_MemberBlank()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType myblank = methods[7];

				Assert.AreEqual("Mommy::myBlankFunction", myblank.NameLong);
				Assert.AreEqual("C Unresolved Public Member Function", myblank.KindName);
				Assert.AreEqual("char *", myblank.TypeText); // The return type
				Assert.IsTrue(null == myblank.Parameters);
				Assert.AreEqual("char * Mommy::myBlankFunction(const char *)", myblank.ToString());
				Assert.AreEqual("", myblank.Attributes);
				Assert.IsFalse(myblank.IsConstructor);
				Assert.IsFalse(myblank.IsAbstract);
				Assert.IsFalse(myblank.IsPrivate);
				Assert.IsFalse(myblank.IsProtected);
				Assert.IsFalse(myblank.IsStatic);
				Assert.IsFalse(myblank.IsVirtual);
			}
		}

		[TestMethod]
		public void MethodTest_Overrides()
		{
			FileEntity fileEnt = Database.LookupFileEntity("base.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			ClassType baseEnt = classtypes[0];
			MethodType[] methods = baseEnt.GetMethods();
			MethodType fn_two_a = methods[1];
			Assert.AreEqual("fn_one", fn_two_a.NameShort);
			MethodType[] fn_two_a_overrides = fn_two_a.GetOverrides();
			Assert.AreEqual(0, fn_two_a_overrides.Length);
			
			MethodType fn_two_b = methods[2];
			Assert.AreEqual("fn_two", fn_two_b.NameShort);
			MethodType[] fn_two_b_overrides = fn_two_b.GetOverrides();
			Assert.AreEqual(3, fn_two_b_overrides.Length);

			Assert.AreEqual("virtual char * Younger::fn_two(const char *)", fn_two_b_overrides[0].ToString(true, false));
			Assert.AreEqual("virtual char * Older::fn_two(const char *)", fn_two_b_overrides[1].ToString(true, false));
			Assert.AreEqual("virtual char * Mommy::fn_two(const char *)", fn_two_b_overrides[2].ToString(true, false));
		}
		[TestMethod]
		public void MethodTest_Inline()
		{
			FileEntity foo_File = Database.LookupFileEntity("foo_Util.h");
			MethodType[] funcs = foo_File.GetFunctionDeclarations();

			// This method has both a declaration, and a definition 
			MethodType funcGetNewMemory = funcs[0];
			Assert.AreEqual("GetNewMemory", funcGetNewMemory.NameSimple);
			Assert.IsFalse(funcGetNewMemory.IsInline);

			MethodType funcMyUnresolvedMethod = funcs[1];
			Assert.IsFalse(funcMyUnresolvedMethod.IsInline);

			MethodType funcBigWide = funcs[2];
			Assert.IsFalse(funcBigWide.IsInline);

			funcs = foo_File.GetFunctionDefinitions();

			MethodType funcGetOldMemory = funcs[0];
			Assert.IsTrue(funcGetOldMemory.IsInline);

			MethodType funcMakeMemory = funcs[1];
			Assert.IsTrue(funcMakeMemory.IsInline);

			ClassType[] classes = foo_File.GetClassTypeDefinitions();
			ClassType CNestedOuter = classes[2];
			MethodType[] classFunctions = CNestedOuter.GetMethods();
			MethodType theCTOR = classFunctions[0];
			Assert.AreEqual("NestedOuter", theCTOR.NameSimple);
			Assert.IsFalse(theCTOR.IsInline);

			MethodType myInlineMethod = classFunctions[1];
			Assert.AreEqual("InLineMethod", myInlineMethod.NameSimple);
			Assert.IsTrue(myInlineMethod.IsInline);
		}

		[TestMethod]
		public void MethodTest_Inline_B()
		{
			FileEntity file = Database.LookupFileEntity("otherbase.h");
			ClassType[] classes = file.GetClassTypeDefinitions();
			ClassType realInlineT = classes[1];
			Assert.IsTrue(realInlineT != null);
			Assert.AreEqual(11, realInlineT.LineDefineStart);
			Assert.AreEqual(16, realInlineT.LineDefineEnd);
			MethodType[] methods = realInlineT.GetMethods();
			Assert.AreEqual(2, methods.Length);
			// This tests the use of the inline keyword.
			// We need to make sure that the line number definitions work for a
			// method when it is defined outside of the class and using the
			// inline keyword.
			MethodType memberMethod = methods[1];
			Assert.AreEqual("AMethod", memberMethod.NameShort);
			Assert.AreEqual(18, memberMethod.LineDefineStart);
			Assert.AreEqual(21, memberMethod.LineDefineEnd);
		}
		[TestMethod]
		public void MethodTest_LexerStuff()
		{
			FileEntity foo_File = Database.LookupFileEntity("foo_Util.h");
			MethodType[] funcs = foo_File.GetFunctionDeclarations();
			MethodType funcBigWide = funcs[2];

			int start = 0;
			int last = 0;
			funcBigWide.GetLexLineNumbers(ref start, ref last); // pass by reference

			Assert.AreEqual(28, start);
			Assert.AreEqual(32, last);
		}
	}
}
